<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>惊蛰的博客 面试-网络基础TCP和UDP的知识</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <style>
        @import url('/css/post-card.css');
        @import url('/css/main.css');
        @import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,400;0,600;1,400;1,600&family=Roboto+Slab:wght@700&display=swap');
    </style>
    <style>
        body {
            font-family: Montserrat, sans;
        }

        .page-footer {
            color: var(--text-p3);
        }

        .sitemap {
            display: flex;
            justify-content: space-between;
            margin: .5rem 0 2rem;
            display: grid;
            grid-gap: 1rem 1rem;
            grid-auto-flow: column dense;
        }

        .sitemap-group {
            display: flex;
            flex-direction: column;
            align-items: flex-start;
        }

        .sitemap-group>.fs14 {
            margin: .5rem 0;
        }

        .page-footer .sitemap .sitemap-group>a {
            margin: .2rem 0;
            color: var(--text-p3);
        }

        .page-footer .text p {
            margin: 4px 0;
            line-height: 1.2;
        }
    </style>
    <script src="https://lib.baomitu.com/jquery/3.6.0/jquery.min.js"></script>
    <script src="/js/index.js"></script>
    <link href="https://cdn.bootcdn.net/ajax/libs/jquery.scrollbar/0.2.9/jquery.scrollbar.min.css" rel="stylesheet">
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery_lazyload/1.9.7/jquery.lazyload.min.js"></script>
<meta name="generator" content="Hexo 5.4.0"></head>

<body>
    
<div class="l_body">
    <div class="l_main list">
        
<div class="nav-wrap mobile-hidden">
    <nav class="sub post cap header1">
        <a  href="/">最近发布</a>
        <a 
            href="/wiki/">分类</a>
        <a 
            href="/notes/">标签</a>
        <a href="/bibi/">说说</a>

    </nav>
    <div class="post-body-title header2">
        面试-网络基础TCP和UDP的知识
    </div>
</div>

<style>
    .sub2 {
        display: flex;
        flex-direction: column;
        position: absolute;
        z-index: 11;
        background:#ffff!important;
        border-radius: 5px;
    }

    .sub2 a{
        display: block;
        margin-left: 0px!important;
        border-radius: 5px;
        margin: 5px 0 3px 0!important;
    }
</style>


<script>
    $(function () {
        //页面初始化的时候，获取滚动条的高度（上次高度）
        var start_height = $(document).scrollTop();
        //获取导航栏的高度(包含 padding 和 border)
        var navigation_height = $('.header1').outerHeight();
        console.log(start_height, navigation_height);
        $(window).scroll(function () {
            //触发滚动事件后，滚动条的高度（本次高度）
            var end_height = $(document).scrollTop();
            console.log(end_height);
            //触发后的高度 与 元素的高度对比
            if (end_height > navigation_height) {
                $('.header1').addClass('hide');
                $('.header2').addClass('hide');
            } else {
                $('.header1').removeClass('hide');
                $('.header2').removeClass('hide');
            }
            //触发后的高度 与 上次触发后的高度 比较
            if (end_height < start_height) {
                $('.header1').removeClass('hide');
                $('.header2').removeClass('hide');
            }
            //再次获取滚动条的高度，用于下次触发事件后的对比
            start_height = $(document).scrollTop();
        });
    });
</script>


        <h2>
            面试-网络基础TCP和UDP的知识
        </h2>

        <div class="body-main-content">
            <h1 id="基本记录一下网络基础-TCP和UDP-的知识"><a href="#基本记录一下网络基础-TCP和UDP-的知识" class="headerlink" title="基本记录一下网络基础(TCP和UDP)的知识"></a>基本记录一下网络基础(TCP和UDP)的知识</h1><p><img src="" data-original="https://i.loli.net/2020/11/30/QRPdCHF1eL3kGB2.png"></p>
<h2 id="UDP和TCP"><a href="#UDP和TCP" class="headerlink" title="UDP和TCP"></a>UDP和TCP</h2><h3 id="UDP"><a href="#UDP" class="headerlink" title="UDP"></a>UDP</h3><p><strong>首先说一下概念，UDP是一种无连接传输层协议，提供面向事务的简单不可靠的信息传输服务</strong></p>
<h4 id="特点："><a href="#特点：" class="headerlink" title="特点："></a>特点：</h4><p><strong>1.udp是无连接的，也就是发送数据包无需建立连接，并因此减少了开销和发送数据之前不必要的时延</strong></p>
<p><strong>2.使用尽量努力交付数据</strong></p>
<p><strong>3.是面向报文的</strong></p>
<h4 id="可能你会有这样的疑问？那么为什么不直接使用IP协议而是要重新定义出一个UDP呢？"><a href="#可能你会有这样的疑问？那么为什么不直接使用IP协议而是要重新定义出一个UDP呢？" class="headerlink" title="可能你会有这样的疑问？那么为什么不直接使用IP协议而是要重新定义出一个UDP呢？"></a>可能你会有这样的疑问？那么为什么不直接使用IP协议而是要重新定义出一个UDP呢？</h4><p><strong>一个重要的原因的是IP协议并没有端口，UDP可以多通道，将数据送到对应的接口里面去</strong></p>
<h2 id="TCP"><a href="#TCP" class="headerlink" title="TCP"></a>TCP</h2><p><strong>首先说一下概念，TCP是一种面向连接、可靠、基于字节流的传输协议，属于5层或者7层网络协议中的传输层协议</strong></p>
<h3 id="特点：-1"><a href="#特点：-1" class="headerlink" title="特点："></a>特点：</h3><p><strong>面向连接：不同于UDP，TCP协议需要通信双方确定彼此已经建立连接后才可以进行数据传输；</strong></p>
<p><strong>可靠：连接建立的双方在进行通信时，TCP保证了不会存在数据丢失，或是数据丢失后存在拯救丢失的措施；字节流：实际传输中，不论是何种数据，TCP都按照字节的方式传输，而非以数据包为单位。</strong></p>
<h3 id="说一下TCP的三次握手，四次挥手，和具体每一步的操作和作用"><a href="#说一下TCP的三次握手，四次挥手，和具体每一步的操作和作用" class="headerlink" title="说一下TCP的三次握手，四次挥手，和具体每一步的操作和作用"></a>说一下TCP的三次握手，四次挥手，和具体每一步的操作和作用</h3><h4 id="简单介绍一下TCP的报文"><a href="#简单介绍一下TCP的报文" class="headerlink" title="简单介绍一下TCP的报文"></a>简单介绍一下TCP的报文</h4><p><img src="" data-original="https://i.loli.net/2020/11/30/U48dMHArty5p9jc.png"></p>
<table data-draft-node="block" data-draft-type="table" data-size="normal"><tbody><tr><th>字段</th><th>含义</th></tr><tr><td>URG</td><td>紧急指针是否有效。为1，表示某一位需要被优先处理</td></tr><tr><td>ACK</td><td>确认号是否有效，一般置为1。</td></tr><tr><td>PSH</td><td>提示接收端应用程序立即从TCP缓冲区把数据读走。</td></tr><tr><td>RST</td><td>对方要求重新建立连接，复位。</td></tr><tr><td>SYN</td><td>请求建立连接，并在其序列号的字段进行序列号的初始值设定。建立连接，设置为1</td></tr><tr><td>FIN</td><td>希望断开连接。</td></tr></tbody></table>

<h3 id="三次握手"><a href="#三次握手" class="headerlink" title="三次握手"></a>三次握手</h3><p><img src="" data-original="https://i.loli.net/2020/11/30/igLxPYQImepJ6Nj.png" alt="三次握手示意图"></p>
<h6 id="第一次握手：建立连接时，客户端发送syn包（syn-x）到服务器，并进入SYN-SENT状态，等待服务器确认；SYN：同步序列编号（Synchronize-Sequence-Numbers）"><a href="#第一次握手：建立连接时，客户端发送syn包（syn-x）到服务器，并进入SYN-SENT状态，等待服务器确认；SYN：同步序列编号（Synchronize-Sequence-Numbers）" class="headerlink" title="第一次握手：建立连接时，客户端发送syn包（syn=x）到服务器，并进入SYN_SENT状态，等待服务器确认；SYN：同步序列编号（Synchronize Sequence Numbers）"></a>第一次握手：建立连接时，客户端发送syn包（syn=x）到服务器，并进入<strong>SYN_SENT</strong>状态，等待服务器确认；SYN：同步序列编号（Synchronize Sequence Numbers）</h6><p>保证了客户端发送正常</p>
<h6 id="第二次握手：服务器收到syn包，必须确认客户的SYN（ack-x-1），同时自己也发送一个SYN包（syn-y），即SYN-ACK包，此时服务器进入SYN-RECV状态；"><a href="#第二次握手：服务器收到syn包，必须确认客户的SYN（ack-x-1），同时自己也发送一个SYN包（syn-y），即SYN-ACK包，此时服务器进入SYN-RECV状态；" class="headerlink" title="第二次握手：服务器收到syn包，必须确认客户的SYN（ack=x+1），同时自己也发送一个SYN包（syn=y），即SYN+ACK包，此时服务器进入SYN_RECV状态；"></a>第二次握手：服务器收到syn包，必须确认客户的SYN（ack=x+1），同时自己也发送一个SYN包（syn=y），即SYN+ACK包，此时服务器进入<strong>SYN_RECV</strong>状态；</h6><p>保证了服务端接受正常，发送正常</p>
<h6 id="第三次握手：客户端收到服务器的SYN-ACK包，向服务器发送确认包ACK-ack-y-1），此包发送完毕，客户端和服务器进入ESTABLISHED（TCP连接成功）状态，完成三次握手。"><a href="#第三次握手：客户端收到服务器的SYN-ACK包，向服务器发送确认包ACK-ack-y-1），此包发送完毕，客户端和服务器进入ESTABLISHED（TCP连接成功）状态，完成三次握手。" class="headerlink" title="第三次握手：客户端收到服务器的SYN+ACK包，向服务器发送确认包ACK(ack=y+1），此包发送完毕，客户端和服务器进入ESTABLISHED（TCP连接成功）状态，完成三次握手。"></a>第三次握手：客户端收到服务器的SYN+ACK包，向服务器发送确认包ACK(ack=y+1），此包发送完毕，客户端和服务器进入<strong>ESTABLISHED</strong>（TCP连接成功）状态，完成三次握手。</h6><p>保证了客户端接受正常，创建连接成功，开始工作</p>
<h3 id="四次挥手"><a href="#四次挥手" class="headerlink" title="四次挥手"></a>四次挥手</h3><p><img src="" data-original="https://i.loli.net/2020/11/30/GQpdIMNCA8PmKfh.png" alt="四次挥手示意图"></p>
<h6 id="1）客户端进程发出连接释放报文，并且停止发送数据。释放数据报文首部，FIN-1，其序列号为seq-u（等于前面已经传送过来的数据的最后一个字节的序号加1），此时，客户端进入FIN-WAIT-1（终止等待1）状态。-TCP规定，FIN报文段即使不携带数据，也要消耗一个序号。"><a href="#1）客户端进程发出连接释放报文，并且停止发送数据。释放数据报文首部，FIN-1，其序列号为seq-u（等于前面已经传送过来的数据的最后一个字节的序号加1），此时，客户端进入FIN-WAIT-1（终止等待1）状态。-TCP规定，FIN报文段即使不携带数据，也要消耗一个序号。" class="headerlink" title="1）客户端进程发出连接释放报文，并且停止发送数据。释放数据报文首部，FIN=1，其序列号为seq=u（等于前面已经传送过来的数据的最后一个字节的序号加1），此时，客户端进入FIN-WAIT-1（终止等待1）状态。 TCP规定，FIN报文段即使不携带数据，也要消耗一个序号。"></a>1）客户端进程发出连接释放报文，并且停止发送数据。释放数据报文首部，FIN=1，其序列号为seq=u（等于前面已经传送过来的数据的最后一个字节的序号加1），此时，客户端进入FIN-WAIT-1（终止等待1）状态。 TCP规定，FIN报文段即使不携带数据，也要消耗一个序号。</h6><h6 id="服务器收到连接释放报文，发出确认报文，ACK-1，ack-u-1，并且带上自己的序列号seq-v，此时，服务端就进入了CLOSE-WAIT（关闭等待）状态。TCP服务器通知高层的应用进程，客户端向服务器的方向就释放了，这时候处于半关闭状态，即客户端已经没有数据要发送了，但是服务器若发送数据，客户端依然要接受。这个状态还要持续一段时间，也就是整个CLOSE-WAIT状态持续的时间。"><a href="#服务器收到连接释放报文，发出确认报文，ACK-1，ack-u-1，并且带上自己的序列号seq-v，此时，服务端就进入了CLOSE-WAIT（关闭等待）状态。TCP服务器通知高层的应用进程，客户端向服务器的方向就释放了，这时候处于半关闭状态，即客户端已经没有数据要发送了，但是服务器若发送数据，客户端依然要接受。这个状态还要持续一段时间，也就是整个CLOSE-WAIT状态持续的时间。" class="headerlink" title="服务器收到连接释放报文，发出确认报文，ACK=1，ack=u+1，并且带上自己的序列号seq=v，此时，服务端就进入了CLOSE-WAIT（关闭等待）状态。TCP服务器通知高层的应用进程，客户端向服务器的方向就释放了，这时候处于半关闭状态，即客户端已经没有数据要发送了，但是服务器若发送数据，客户端依然要接受。这个状态还要持续一段时间，也就是整个CLOSE-WAIT状态持续的时间。"></a>服务器收到连接释放报文，发出确认报文，ACK=1，ack=u+1，并且带上自己的序列号seq=v，此时，服务端就进入了CLOSE-WAIT（关闭等待）状态。TCP服务器通知高层的应用进程，客户端向服务器的方向就释放了，这时候处于半关闭状态，即客户端已经没有数据要发送了，但是服务器若发送数据，客户端依然要接受。这个状态还要持续一段时间，也就是整个CLOSE-WAIT状态持续的时间。</h6><h6 id="（中断中发送未完成数据流-）客户端收到服务器的确认请求后，此时，客户端就进入FIN-WAIT-2（终止等待2）状态，等待服务器发送连接释放报文（在这之前还需要接受服务器发送的最后的数据）。"><a href="#（中断中发送未完成数据流-）客户端收到服务器的确认请求后，此时，客户端就进入FIN-WAIT-2（终止等待2）状态，等待服务器发送连接释放报文（在这之前还需要接受服务器发送的最后的数据）。" class="headerlink" title="（中断中发送未完成数据流 ）客户端收到服务器的确认请求后，此时，客户端就进入FIN-WAIT-2（终止等待2）状态，等待服务器发送连接释放报文（在这之前还需要接受服务器发送的最后的数据）。"></a>（中断中发送未完成数据流 ）客户端收到服务器的确认请求后，此时，客户端就进入FIN-WAIT-2（终止等待2）状态，等待服务器发送连接释放报文（在这之前还需要接受服务器发送的最后的数据）。</h6><h6 id="2）服务器将最后的数据发送完毕后，就向客户端发送连接释放报文，FIN-1，ack-u-1，由于在半关闭状态，服务器很可能又发送了一些数据，假定此时的序列号为seq-w，此时，服务器就进入了LAST-ACK（最后确认）状态，等待客户端的确认。"><a href="#2）服务器将最后的数据发送完毕后，就向客户端发送连接释放报文，FIN-1，ack-u-1，由于在半关闭状态，服务器很可能又发送了一些数据，假定此时的序列号为seq-w，此时，服务器就进入了LAST-ACK（最后确认）状态，等待客户端的确认。" class="headerlink" title="2）服务器将最后的数据发送完毕后，就向客户端发送连接释放报文，FIN=1，ack=u+1，由于在半关闭状态，服务器很可能又发送了一些数据，假定此时的序列号为seq=w，此时，服务器就进入了LAST-ACK（最后确认）状态，等待客户端的确认。"></a>2）服务器将最后的数据发送完毕后，就向客户端发送连接释放报文，FIN=1，ack=u+1，由于在半关闭状态，服务器很可能又发送了一些数据，假定此时的序列号为seq=w，此时，服务器就进入了LAST-ACK（最后确认）状态，等待客户端的确认。</h6><h6 id="3）客户端收到服务器的连接释放报文后，必须发出确认，ACK-1，ack-w-1，而自己的序列号是seq-u-1，此时，客户端就进入了TIME-WAIT（时间等待）状态。注意此时TCP连接还没有释放，必须经过2∗∗MSL（最长报文段寿命）的时间后，当客户端撤销相应的TCB后，才进入CLOSED状态。"><a href="#3）客户端收到服务器的连接释放报文后，必须发出确认，ACK-1，ack-w-1，而自己的序列号是seq-u-1，此时，客户端就进入了TIME-WAIT（时间等待）状态。注意此时TCP连接还没有释放，必须经过2∗∗MSL（最长报文段寿命）的时间后，当客户端撤销相应的TCB后，才进入CLOSED状态。" class="headerlink" title="3）客户端收到服务器的连接释放报文后，必须发出确认，ACK=1，ack=w+1，而自己的序列号是seq=u+1，此时，客户端就进入了TIME-WAIT（时间等待）状态。注意此时TCP连接还没有释放，必须经过2∗∗MSL（最长报文段寿命）的时间后，当客户端撤销相应的TCB后，才进入CLOSED状态。"></a>3）客户端收到服务器的连接释放报文后，必须发出确认，ACK=1，ack=w+1，而自己的序列号是seq=u+1，此时，客户端就进入了TIME-WAIT（时间等待）状态。注意此时TCP连接还没有释放，必须经过2∗∗MSL（最长报文段寿命）的时间后，当客户端撤销相应的TCB后，才进入CLOSED状态。</h6><h6 id="4）服务器只要收到了客户端发出的确认，立即进入CLOSED状态。同样，撤销TCB后，就结束了这次的TCP连接。可以看到，服务器结束TCP连接的时间要比客户端早一些。"><a href="#4）服务器只要收到了客户端发出的确认，立即进入CLOSED状态。同样，撤销TCB后，就结束了这次的TCP连接。可以看到，服务器结束TCP连接的时间要比客户端早一些。" class="headerlink" title="4）服务器只要收到了客户端发出的确认，立即进入CLOSED状态。同样，撤销TCB后，就结束了这次的TCP连接。可以看到，服务器结束TCP连接的时间要比客户端早一些。"></a>4）服务器只要收到了客户端发出的确认，立即进入CLOSED状态。同样，撤销TCB后，就结束了这次的TCP连接。可以看到，服务器结束TCP连接的时间要比客户端早一些。</h6><h3 id="关于TCP的面试题比较多一些，下面罗列几个面试题（网上总结的）："><a href="#关于TCP的面试题比较多一些，下面罗列几个面试题（网上总结的）：" class="headerlink" title="关于TCP的面试题比较多一些，下面罗列几个面试题（网上总结的）："></a>关于TCP的面试题比较多一些，下面罗列几个面试题（网上总结的）：</h3><h6 id="【问题1】为什么连接的时候是三次握手，关闭的时候却是四次握手？"><a href="#【问题1】为什么连接的时候是三次握手，关闭的时候却是四次握手？" class="headerlink" title="【问题1】为什么连接的时候是三次握手，关闭的时候却是四次握手？"></a>【问题1】为什么连接的时候是三次握手，关闭的时候却是四次握手？</h6><h6 id="答：因为当Server端收到Client端的SYN连接请求报文后，可以直接发送SYN-ACK报文。其中ACK报文是用来应答的，SYN报文是用来同步的。但是关闭连接时，当Server端收到FIN报文时，很可能并不会立即关闭SOCKET，所以只能先回复一个ACK报文，告诉Client端，”你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了，我才能发送FIN报文，因此不能一起发送。故需要四步握手。"><a href="#答：因为当Server端收到Client端的SYN连接请求报文后，可以直接发送SYN-ACK报文。其中ACK报文是用来应答的，SYN报文是用来同步的。但是关闭连接时，当Server端收到FIN报文时，很可能并不会立即关闭SOCKET，所以只能先回复一个ACK报文，告诉Client端，”你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了，我才能发送FIN报文，因此不能一起发送。故需要四步握手。" class="headerlink" title="答：因为当Server端收到Client端的SYN连接请求报文后，可以直接发送SYN+ACK报文。其中ACK报文是用来应答的，SYN报文是用来同步的。但是关闭连接时，当Server端收到FIN报文时，很可能并不会立即关闭SOCKET，所以只能先回复一个ACK报文，告诉Client端，”你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了，我才能发送FIN报文，因此不能一起发送。故需要四步握手。"></a>答：因为当Server端收到Client端的SYN连接请求报文后，可以直接发送SYN+ACK报文。其中ACK报文是用来应答的，SYN报文是用来同步的。但是关闭连接时，当Server端收到FIN报文时，很可能并不会立即关闭SOCKET，所以只能先回复一个ACK报文，告诉Client端，”你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了，我才能发送FIN报文，因此不能一起发送。故需要四步握手。</h6><h6 id="【问题2】为什么TIME-WAIT状态需要经过2MSL-最大报文段生存时间-才能返回到CLOSE状态？"><a href="#【问题2】为什么TIME-WAIT状态需要经过2MSL-最大报文段生存时间-才能返回到CLOSE状态？" class="headerlink" title="【问题2】为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态？"></a>【问题2】为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态？</h6><h6 id="答：虽然按道理，四个报文都发送完毕，我们可以直接进入CLOSE状态了，但是我们必须假象网络是不可靠的，有可以最后一个ACK丢失。所以TIME-WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复，但该ACK可能丢失。Server如果没有收到ACK，将不断重复发送FIN片段。所以Client不能立即关闭，它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME-WAIT状态。Client会设置一个计时器，等待2MSL的时间。如果在该时间内再次收到FIN，那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL-Maximum-Segment-Lifetime-。MSL指一个片段在网络中最大的存活时间，2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL，Client都没有再次收到FIN，那么Client推断ACK已经被成功接收，则结束TCP连接。"><a href="#答：虽然按道理，四个报文都发送完毕，我们可以直接进入CLOSE状态了，但是我们必须假象网络是不可靠的，有可以最后一个ACK丢失。所以TIME-WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复，但该ACK可能丢失。Server如果没有收到ACK，将不断重复发送FIN片段。所以Client不能立即关闭，它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME-WAIT状态。Client会设置一个计时器，等待2MSL的时间。如果在该时间内再次收到FIN，那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL-Maximum-Segment-Lifetime-。MSL指一个片段在网络中最大的存活时间，2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL，Client都没有再次收到FIN，那么Client推断ACK已经被成功接收，则结束TCP连接。" class="headerlink" title="答：虽然按道理，四个报文都发送完毕，我们可以直接进入CLOSE状态了，但是我们必须假象网络是不可靠的，有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复，但该ACK可能丢失。Server如果没有收到ACK，将不断重复发送FIN片段。所以Client不能立即关闭，它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器，等待2MSL的时间。如果在该时间内再次收到FIN，那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间，2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL，Client都没有再次收到FIN，那么Client推断ACK已经被成功接收，则结束TCP连接。"></a>答：虽然按道理，四个报文都发送完毕，我们可以直接进入CLOSE状态了，但是我们必须假象网络是不可靠的，有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复，但该ACK可能丢失。Server如果没有收到ACK，将不断重复发送FIN片段。所以Client不能立即关闭，它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器，等待2MSL的时间。如果在该时间内再次收到FIN，那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间，2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL，Client都没有再次收到FIN，那么Client推断ACK已经被成功接收，则结束TCP连接。</h6><h6 id="【问题3】为什么不能用两次握手进行连接？"><a href="#【问题3】为什么不能用两次握手进行连接？" class="headerlink" title="【问题3】为什么不能用两次握手进行连接？"></a>【问题3】为什么不能用两次握手进行连接？</h6><h6 id="答：3次握手完成两个重要的功能，既要双方做好发送数据的准备工作-双方都知道彼此已准备好-，也要允许双方就初始序列号进行协商，这个序列号在握手过程中被发送和确认。"><a href="#答：3次握手完成两个重要的功能，既要双方做好发送数据的准备工作-双方都知道彼此已准备好-，也要允许双方就初始序列号进行协商，这个序列号在握手过程中被发送和确认。" class="headerlink" title="答：3次握手完成两个重要的功能，既要双方做好发送数据的准备工作(双方都知道彼此已准备好)，也要允许双方就初始序列号进行协商，这个序列号在握手过程中被发送和确认。"></a>答：3次握手完成两个重要的功能，既要双方做好发送数据的准备工作(双方都知道彼此已准备好)，也要允许双方就初始序列号进行协商，这个序列号在握手过程中被发送和确认。</h6><p>  ###### 现在把三次握手改成仅需要两次握手，死锁是可能发生的。作为例子，考虑计算机S和C之间的通信，假定C给S发送一个连接请求分组，S收到了这个分组，并发 送了确认应答分组。按照两次握手的协定，S认为连接已经成功地建立了，可以开始发送数据分组。可是，C在S的应答分组在传输中被丢失的情况下，将不知道S 是否已准备好，不知道S建立什么样的序列号，C甚至怀疑S是否收到自己的连接请求分组。在这种情况下，C认为连接还未建立成功，将忽略S发来的任何数据分 组，只等待连接确认应答分组。而S在发出的分组超时后，重复发送同样的分组。这样就形成了死锁。</p>
<h6 id="【问题4】如果已经建立了连接，但是客户端突然出现故障了怎么办？TCP还设有一个保活计时器，显然，客户端如果出现故障，服务器不能一直等下去，白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器，时间通常是设置为2小时，若两小时还没有收到客户端的任何数据，服务器就会发送一个探测报文段，以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应，服务器就认为客户端出了故障，接着就关闭连接。"><a href="#【问题4】如果已经建立了连接，但是客户端突然出现故障了怎么办？TCP还设有一个保活计时器，显然，客户端如果出现故障，服务器不能一直等下去，白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器，时间通常是设置为2小时，若两小时还没有收到客户端的任何数据，服务器就会发送一个探测报文段，以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应，服务器就认为客户端出了故障，接着就关闭连接。" class="headerlink" title="【问题4】如果已经建立了连接，但是客户端突然出现故障了怎么办？TCP还设有一个保活计时器，显然，客户端如果出现故障，服务器不能一直等下去，白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器，时间通常是设置为2小时，若两小时还没有收到客户端的任何数据，服务器就会发送一个探测报文段，以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应，服务器就认为客户端出了故障，接着就关闭连接。"></a>【问题4】如果已经建立了连接，但是客户端突然出现故障了怎么办？TCP还设有一个保活计时器，显然，客户端如果出现故障，服务器不能一直等下去，白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器，时间通常是设置为2小时，若两小时还没有收到客户端的任何数据，服务器就会发送一个探测报文段，以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应，服务器就认为客户端出了故障，接着就关闭连接。</h6><h3 id="说一下TCP和UDP有什么不同处"><a href="#说一下TCP和UDP有什么不同处" class="headerlink" title="说一下TCP和UDP有什么不同处"></a>说一下TCP和UDP有什么不同处</h3><h6 id="1、-TCP面向连接-（如打电话要先拨号建立连接）-UDP是无连接-的，即发送数据之前不需要建立连接"><a href="#1、-TCP面向连接-（如打电话要先拨号建立连接）-UDP是无连接-的，即发送数据之前不需要建立连接" class="headerlink" title="1、 TCP面向连接 （如打电话要先拨号建立连接）; UDP是无连接 的，即发送数据之前不需要建立连接"></a>1、 TCP面向连接 （如打电话要先拨号建立连接）; UDP是无连接 的，即发送数据之前不需要建立连接</h6><h6 id="2、TCP提供可靠的服务。也就是说，通过TCP连接传送的数据，无差错，不丢失，不重复，且按序到达-UDP尽最大努力交付，即不保证可靠交付"><a href="#2、TCP提供可靠的服务。也就是说，通过TCP连接传送的数据，无差错，不丢失，不重复，且按序到达-UDP尽最大努力交付，即不保证可靠交付" class="headerlink" title="2、TCP提供可靠的服务。也就是说，通过TCP连接传送的数据，无差错，不丢失，不重复，且按序到达;UDP尽最大努力交付，即不保证可靠交付"></a>2、TCP提供可靠的服务。也就是说，通过TCP连接传送的数据，无差错，不丢失，不重复，且按序到达;UDP尽最大努力交付，即不保证可靠交付</h6><h6 id="Tcp通过校验和，重传控制，序号标识，滑动窗口、确认应答实现可靠传输。如丢包时的重发控制，还可以对次序乱掉的分包进行顺序控制。"><a href="#Tcp通过校验和，重传控制，序号标识，滑动窗口、确认应答实现可靠传输。如丢包时的重发控制，还可以对次序乱掉的分包进行顺序控制。" class="headerlink" title="Tcp通过校验和，重传控制，序号标识，滑动窗口、确认应答实现可靠传输。如丢包时的重发控制，还可以对次序乱掉的分包进行顺序控制。"></a>Tcp通过校验和，重传控制，序号标识，滑动窗口、确认应答实现可靠传输。如丢包时的重发控制，还可以对次序乱掉的分包进行顺序控制。</h6><h6 id="3、UDP具有较好的实时性，工作效率比TCP高，适用于对高速传输和实时性有较高的通信或广播通信。"><a href="#3、UDP具有较好的实时性，工作效率比TCP高，适用于对高速传输和实时性有较高的通信或广播通信。" class="headerlink" title="3、UDP具有较好的实时性，工作效率比TCP高，适用于对高速传输和实时性有较高的通信或广播通信。"></a>3、UDP具有较好的实时性，工作效率比TCP高，适用于对高速传输和实时性有较高的通信或广播通信。</h6><h6 id="4-每一条TCP连接只能是点到点的-UDP支持一对一，一对多，多对一和多对多的交互通信"><a href="#4-每一条TCP连接只能是点到点的-UDP支持一对一，一对多，多对一和多对多的交互通信" class="headerlink" title="4.每一条TCP连接只能是点到点的;UDP支持一对一，一对多，多对一和多对多的交互通信"></a>4.每一条TCP连接只能是点到点的;UDP支持一对一，一对多，多对一和多对多的交互通信</h6><h6 id="5、TCP对系统资源要求较多，UDP对系统资源要求较少。"><a href="#5、TCP对系统资源要求较多，UDP对系统资源要求较少。" class="headerlink" title="5、TCP对系统资源要求较多，UDP对系统资源要求较少。"></a>5、TCP对系统资源要求较多，UDP对系统资源要求较少。</h6><h3 id="TCP那么好，那么为什么还需要UDP，UDP相对的优势在哪里"><a href="#TCP那么好，那么为什么还需要UDP，UDP相对的优势在哪里" class="headerlink" title="TCP那么好，那么为什么还需要UDP，UDP相对的优势在哪里"></a>TCP那么好，那么为什么还需要UDP，UDP相对的优势在哪里</h3><h6 id="UDP以其简单、传输快的优势，在越来越多场景下取代了TCP-如实时游戏。"><a href="#UDP以其简单、传输快的优势，在越来越多场景下取代了TCP-如实时游戏。" class="headerlink" title="UDP以其简单、传输快的优势，在越来越多场景下取代了TCP,如实时游戏。"></a>UDP以其简单、传输快的优势，在越来越多场景下取代了TCP,如实时游戏。</h6><h6 id="（1）网速的提升给UDP的稳定性提供可靠网络保障，丢包率很低，如果使用应用层重传，能够确保传输的可靠性。"><a href="#（1）网速的提升给UDP的稳定性提供可靠网络保障，丢包率很低，如果使用应用层重传，能够确保传输的可靠性。" class="headerlink" title="（1）网速的提升给UDP的稳定性提供可靠网络保障，丢包率很低，如果使用应用层重传，能够确保传输的可靠性。"></a>（1）网速的提升给UDP的稳定性提供可靠网络保障，丢包率很低，如果使用应用层重传，能够确保传输的可靠性。</h6><h6 id="（2）TCP为了实现网络通信的可靠性，使用了复杂的拥塞控制算法，建立了繁琐的握手过程，由于TCP内置的系统协议栈中，极难对其进行改进。"><a href="#（2）TCP为了实现网络通信的可靠性，使用了复杂的拥塞控制算法，建立了繁琐的握手过程，由于TCP内置的系统协议栈中，极难对其进行改进。" class="headerlink" title="（2）TCP为了实现网络通信的可靠性，使用了复杂的拥塞控制算法，建立了繁琐的握手过程，由于TCP内置的系统协议栈中，极难对其进行改进。"></a>（2）TCP为了实现网络通信的可靠性，使用了复杂的拥塞控制算法，建立了繁琐的握手过程，由于TCP内置的系统协议栈中，极难对其进行改进。</h6><h6 id="采用TCP，一旦发生丢包，TCP会将后续的包缓存起来，等前面的包重传并接收到后再继续发送，延时会越来越大，基于UDP对实时性要求较为严格的情况下，采用自定义重传机制，能够把丢包产生的延迟降到最低，尽量减少网络问题对游戏性造成影响。"><a href="#采用TCP，一旦发生丢包，TCP会将后续的包缓存起来，等前面的包重传并接收到后再继续发送，延时会越来越大，基于UDP对实时性要求较为严格的情况下，采用自定义重传机制，能够把丢包产生的延迟降到最低，尽量减少网络问题对游戏性造成影响。" class="headerlink" title="采用TCP，一旦发生丢包，TCP会将后续的包缓存起来，等前面的包重传并接收到后再继续发送，延时会越来越大，基于UDP对实时性要求较为严格的情况下，采用自定义重传机制，能够把丢包产生的延迟降到最低，尽量减少网络问题对游戏性造成影响。"></a>采用TCP，一旦发生丢包，TCP会将后续的包缓存起来，等前面的包重传并接收到后再继续发送，延时会越来越大，基于UDP对实时性要求较为严格的情况下，采用自定义重传机制，能够把丢包产生的延迟降到最低，尽量减少网络问题对游戏性造成影响。</h6><h3 id="如何让UDP更不易丢包，变成可靠的UDP呢？"><a href="#如何让UDP更不易丢包，变成可靠的UDP呢？" class="headerlink" title="如何让UDP更不易丢包，变成可靠的UDP呢？"></a>如何让UDP更不易丢包，变成可靠的UDP呢？</h3><h6 id="我觉得这个问题比较复杂，咱们可以单独开一篇文章说明"><a href="#我觉得这个问题比较复杂，咱们可以单独开一篇文章说明" class="headerlink" title="我觉得这个问题比较复杂，咱们可以单独开一篇文章说明"></a>我觉得这个问题比较复杂，咱们可以单独开一篇文章说明</h6><h6 id="以上就是我整理的TCP和UDP的相关面试知识"><a href="#以上就是我整理的TCP和UDP的相关面试知识" class="headerlink" title="以上就是我整理的TCP和UDP的相关面试知识"></a>以上就是我整理的TCP和UDP的相关面试知识</h6>
        </div>
        <div class="page-footer reveal fs12">
    <hr>
    <div class="sitemap">
        <div class="sitemap-group">
            <span class="fs14">博客</span>
            <a href="/">近期发布</a>
            <a href="/wiki/">分类</a>
            <a href="/notes/">标签</a>
            <a href="/archives/">归档</a>
        </div>
        <div class="sitemap-group">
            <span class="fs14">社交</span>
            <a target="_blank" rel="external nofollow noopener noreferrer" href="">GitHub</a>
            <a target="_blank" rel="external nofollow noopener noreferrer" href="">GitLab</a>
        </div>
        <div class="sitemap-group">
            <span class="fs14">更多</span>
            <a href="/about/">关于本站</a>
            <a href="/bibi/">哔哔</a>
            <a target="_blank" rel="external nofollow noopener noreferrer" href="https://image.jingzhe.xyz">图床</a>
        </div>
    </div>
    <div class="text">
        <p>本博客所有文章除特别声明外，均采用
            <a target="_blank" rel="external nofollow noopener noreferrer"
                href="https://creativecommons.org/licenses/by-nc-sa/4.0/">
                CCBY-NC-SA 4.0
            </a>
            许可协议，转载请注明出处。
        </p>
    </div>
</div>
    </div>
    <aside class="l_right">
        
<header class="header">
    <div class="logo-wrap">
        <a class="avatar" href="/about/">
            <img class="avatar" src="" data-original="https://ae01.alicdn.com/kf/Ua26a9ebfe30847ff8d4d7d7c7647c61cH.jpg"></a>
        <a class="title" href="/">
            <div class="main">惊蛰</div>
            <div class="sub normal cap"></div>
            <div class="sub hover cap" style="opacity:0">jingzhe.xyz</div>
        </a>
    </div>
    <nav class="menu dis-select">
        <a class="nav-item " href="/">博客</a>
        <a class="nav-item " href="/archives/">归档</a>
        <a class="nav-item " href="/about/">关于</a>
    </nav>
</header>
<script>
    $(function () {
        // https://v1.hitokoto.cn/?c=f&encode=text&max_length=8
        $.ajax({
            url: "https://v1.hitokoto.cn/?c=f&encode=text&max_length=10&min_length=5&c=i",
            success: function (result) {
                $(".normal").html(result);
            }
        });

    })
</script>
<div class="widgets">
    <div class="widget-wrap">
    <div class="widget-header cap dis-select"><span class="name">目录</span></div>
    <div class="widget-body fs14 toc-body">
        <ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%9F%BA%E6%9C%AC%E8%AE%B0%E5%BD%95%E4%B8%80%E4%B8%8B%E7%BD%91%E7%BB%9C%E5%9F%BA%E7%A1%80-TCP%E5%92%8CUDP-%E7%9A%84%E7%9F%A5%E8%AF%86"><span class="toc-text">基本记录一下网络基础(TCP和UDP)的知识</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#UDP%E5%92%8CTCP"><span class="toc-text">UDP和TCP</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#UDP"><span class="toc-text">UDP</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#TCP"><span class="toc-text">TCP</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%89%B9%E7%82%B9%EF%BC%9A-1"><span class="toc-text">特点：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%AF%B4%E4%B8%80%E4%B8%8BTCP%E7%9A%84%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B%EF%BC%8C%E5%9B%9B%E6%AC%A1%E6%8C%A5%E6%89%8B%EF%BC%8C%E5%92%8C%E5%85%B7%E4%BD%93%E6%AF%8F%E4%B8%80%E6%AD%A5%E7%9A%84%E6%93%8D%E4%BD%9C%E5%92%8C%E4%BD%9C%E7%94%A8"><span class="toc-text">说一下TCP的三次握手，四次挥手，和具体每一步的操作和作用</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B"><span class="toc-text">三次握手</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%9B%9B%E6%AC%A1%E6%8C%A5%E6%89%8B"><span class="toc-text">四次挥手</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%85%B3%E4%BA%8ETCP%E7%9A%84%E9%9D%A2%E8%AF%95%E9%A2%98%E6%AF%94%E8%BE%83%E5%A4%9A%E4%B8%80%E4%BA%9B%EF%BC%8C%E4%B8%8B%E9%9D%A2%E7%BD%97%E5%88%97%E5%87%A0%E4%B8%AA%E9%9D%A2%E8%AF%95%E9%A2%98%EF%BC%88%E7%BD%91%E4%B8%8A%E6%80%BB%E7%BB%93%E7%9A%84%EF%BC%89%EF%BC%9A"><span class="toc-text">关于TCP的面试题比较多一些，下面罗列几个面试题（网上总结的）：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%AF%B4%E4%B8%80%E4%B8%8BTCP%E5%92%8CUDP%E6%9C%89%E4%BB%80%E4%B9%88%E4%B8%8D%E5%90%8C%E5%A4%84"><span class="toc-text">说一下TCP和UDP有什么不同处</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#TCP%E9%82%A3%E4%B9%88%E5%A5%BD%EF%BC%8C%E9%82%A3%E4%B9%88%E4%B8%BA%E4%BB%80%E4%B9%88%E8%BF%98%E9%9C%80%E8%A6%81UDP%EF%BC%8CUDP%E7%9B%B8%E5%AF%B9%E7%9A%84%E4%BC%98%E5%8A%BF%E5%9C%A8%E5%93%AA%E9%87%8C"><span class="toc-text">TCP那么好，那么为什么还需要UDP，UDP相对的优势在哪里</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%A6%82%E4%BD%95%E8%AE%A9UDP%E6%9B%B4%E4%B8%8D%E6%98%93%E4%B8%A2%E5%8C%85%EF%BC%8C%E5%8F%98%E6%88%90%E5%8F%AF%E9%9D%A0%E7%9A%84UDP%E5%91%A2%EF%BC%9F"><span class="toc-text">如何让UDP更不易丢包，变成可靠的UDP呢？</span></a></li></ol></li></ol></li></ol>
    </div>

    <!-- 
     -->
</div>

<script>
    // 让锚点位置下降80个点数
    $(".body-main-content *[id]").each(i => {
        $($(".body-main-content *[id]")[i]).attr('style', 'padding-top: 60px;margin-top: -60px;');
    })

    $(function () {
        $('.toc-link').click(function () {
            if (location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') && location
                .hostname == this.hostname) {
                var $target = $(this);
                $target = $('[id=' + decodeURI(this.hash.slice(1)) + ']');
                if ($target.length) {
                    var targetOffset = $target.offset().top;
                    $('html,body').animate({
                            scrollTop: targetOffset
                        },
                        700);
                    return false;
                }
            }
        });
    })
</script>
    <footer class="footer dis-select">
    <div class="social-wrap">
        <a class="social" title="GitHub" href="https://github.com/xaoxuu" target="_blank"
            rel="external nofollow noopener noreferrer"><img class="lazy entered loaded"
                src="https://cdn.jsdelivr.net/gh/cdn-x/placeholder@1.0.3/social/08a41b181ce68.svg"
                data-src="https://cdn.jsdelivr.net/gh/cdn-x/placeholder@1.0.3/social/08a41b181ce68.svg"
                data-ll-status="loaded"></a><a class="social" title="Spotify"
            href="https://open.spotify.com/user/xaoxuu" target="_blank"
            rel="external nofollow noopener noreferrer"><img class="lazy entered loaded"
                src="https://cdn.jsdelivr.net/gh/cdn-x/placeholder@1.0.3/social/3845874.svg"
                data-src="https://cdn.jsdelivr.net/gh/cdn-x/placeholder@1.0.3/social/3845874.svg"
                data-ll-status="loaded"></a><a class="social" title="Unsplash"
            href="https://unsplash.com/@xaoxuu" target="_blank"
            rel="external nofollow noopener noreferrer"><img class="lazy entered loaded"
                src="https://cdn.jsdelivr.net/gh/cdn-x/placeholder@1.0.3/social/3616429.svg"
                data-src="https://cdn.jsdelivr.net/gh/cdn-x/placeholder@1.0.3/social/3616429.svg"
                data-ll-status="loaded"></a><a class="social" title="Comments" href="/about/#comments"
            rel="noopener noreferrer"><img class="lazy entered loaded"
                src="https://cdn.jsdelivr.net/gh/cdn-x/placeholder@1.0.3/social/942ebbf1a4b91.svg"
                data-src="https://cdn.jsdelivr.net/gh/cdn-x/placeholder@1.0.3/social/942ebbf1a4b91.svg"
                data-ll-status="loaded"></a></div>
</footer>
</div>
    </aside>
</div>

<style>

</style>
    <div class="loading-div" id="loading" style="display: none;">
    <div class="loading">
        <svg id="stage" viewBox="0 0 500 500" preserveAspectRatio="xMidYMid meet" stroke="#fff" stroke-width="3"
            stroke-linecap="round" fill="none"></svg>
        <span>加载中...</span>
    </div>
</div>
<style>
    .loading-div {
        position: absolute;
        display: flex;
        top: 0px;
        width: 100%;
        height: 100%;
        align-items: center;
        z-index: 20;
        animation-name: fadeIn;
        animation-duration: 2s;
        animation-fill-mode: forwards;
    }

    /*动画效果*/
    @keyframes fadeIn {
        from {
            backdrop-filter: blur(0px);
            background: rgba(0, 0, 0, 0);
        }

        to {
            backdrop-filter: blur(2px);
            background: rgb(0, 0, 0, 0.5);
        }
    }

    /*动画效果*/
    @keyframes fadeIn1 {
        from {
            filter: blur(1px);
        }

        to {
            filter: blur(0px);
        }
    }

    .loading {
        color: #fff;
        width: 250px;
        height: 250px;
        margin: 0 auto;
        display: flex;
        align-items: center;
        justify-content: center;
        align-content: center;
        flex-wrap: nowrap;
        flex-direction: column;
        animation-name: fadeIn1;
        animation-duration: 2s;
        animation-fill-mode: forwards;
    }

    svg {
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
        /* background: #000; */
    }
</style>
<script src="https://lib.baomitu.com/gsap/3.7.1/gsap.min.js"></script>
<script>
    let pts = [],
        nPts = 12,
        lineLength = 60,
        timeScale = 0.5

    const radius = 180,
        tl = gsap.timeline()

    for (let i = 0; i < nPts; i++) { // plot points + add circles
        const c = document.createElementNS("http://www.w3.org/2000/svg", "circle"),
            angle = (i / nPts * Math.PI * 2) - Math.PI / 2,
            x = Math.cos(angle) * radius,
            y = Math.sin(angle) * radius

        pts.push(x.toFixed(2) + ',' + y.toFixed(2) + ' ')

        gsap.set(c, {
            x: 250,
            y: 250,
            scale: 0.8,
            attr: {
                class: 'c' + i,
                r: 3,
                cx: x,
                cy: y,
                fill: '#fff',
                stroke: 'none'
            }
        })

        stage.appendChild(c);
    }


    for (let i = 0; i <= nPts; i++) { // add paths + animate
        const p = document.createElementNS("http://www.w3.org/2000/svg", "path")

        gsap.set(p, {
            x: 250,
            y: 250,
            attr: {
                class: 'line' + i,
                d: 'M' + pts[i] + ' C' + gsap.utils.wrap(pts, [i + 2]) + ' ' + gsap.utils.wrap(pts, [i - 5]) +
                    ' ' + gsap.utils.wrap(pts, [i - 2]),
                // d:'M'+pts[i]+' c 0,0 '+gsap.utils.wrap(pts,[i-nPts/2])+' '+gsap.utils.wrap(pts,[i-3]),
                'stroke-dasharray': lineLength + ' ' + lineLength,
                'stroke-dashoffset': lineLength
            },
        });

        stage.appendChild(p);

        const lineTL = gsap.timeline({
                repeat: -1,
                defaults: {
                    duration: 0.4
                }
            })
            .to(p, {
                attr: {
                    'stroke-dashoffset': -lineLength
                },
                ease: 'expo.inOut',
                duration: 0.6
            }, 0.4)

        if (i < nPts) {
            lineTL.to('.c' + i, {
                scale: 1.2,
                ease: 'expo.inOut'
            }, 0.1)
            lineTL.to('.c' + i, {
                scale: 0.8,
                ease: 'expo.in'
            }, 0.5)
        }

        tl.add(lineTL, 1 - i / nPts);
    }

    tl.play(5).timeScale(timeScale)
</script>
<script>
    $(function () {
        // loadingShow()
    })

    function loadingShow() {
        $("#loading").show();
    }

    function loadingHide() {
        $("#loading").hide();
    }
</script>

    <!-- <script src="https://cdn.bootcdn.net/ajax/libs/jquery.scrollbar/0.2.9/jquery.scrollbar.min.js"></script> -->
    <script>
        // $(document).ready(function () {
        //     $('.l_body').scrollbar({
        //         barWidth: 10, //滚动条的宽度(这里根据需要写数值即可，不设置是10,即默认10px)
        //         position: "x,y", //写“x”代表只出水平滚动条，写“y”表示只出垂直滚动条，写“x,y”则出水平和垂直滚动条（只有在内容超出容器时才出现滚动条）
        //         wheelDis: 15 //滚轮滚动一次向下或向上滚动的距离，默认是15，可根据需要修改数值
        //     });
        // });
    </script>
    <script>
        $('img').lazyload({
            threshold: 0,
            failure_limit: 0,
            event: "scroll", //触发事件
            effect: "show", //显示方式
            container: window, //容器
            data_attribute: "original", //属性
            skip_invisible: true,
            appear: null,
            load: null,
            placeholder: ""
        });
    </script>
<script>
            window.imageLazyLoadSetting = {
                isSPA: false,
                preloadRatio: 3,
                processImages: null,
            };
        </script><script>window.addEventListener("load",function(){var t=/\.(gif|jpg|jpeg|tiff|png)$/i,r=/^data:image\/[a-z]+;base64,/;Array.prototype.slice.call(document.querySelectorAll("img[data-original]")).forEach(function(a){var e=a.parentNode;"A"===e.tagName&&(e.href.match(t)||e.href.match(r))&&(e.href=a.dataset.original)})});</script><script>!function(n){n.imageLazyLoadSetting.processImages=o;var e=n.imageLazyLoadSetting.isSPA,i=n.imageLazyLoadSetting.preloadRatio||1,r=Array.prototype.slice.call(document.querySelectorAll("img[data-original]"));function o(){e&&(r=Array.prototype.slice.call(document.querySelectorAll("img[data-original]")));for(var t,a=0;a<r.length;a++)0<=(t=(t=r[a]).getBoundingClientRect()).bottom&&0<=t.left&&t.top<=(n.innerHeight*i||document.documentElement.clientHeight*i)&&function(){var t,e,n,i,o=r[a];t=o,e=function(){r=r.filter(function(t){return o!==t})},n=new Image,i=t.getAttribute("data-original"),n.onload=function(){t.src=i,e&&e()},t.src!==i&&(n.src=i)}()}o(),n.addEventListener("scroll",function(){var t,e;t=o,e=n,clearTimeout(t.tId),t.tId=setTimeout(function(){t.call(e)},500)})}(this);</script></body>